package com.sprouting.metadata.core.model;

import com.sprouting.metadata.core.interfaces.MetadataConstant;
import lombok.Data;

import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

/**
 * java全限定名,就是java的类信息
 *
 * @author ：LX（长沙麓谷）
 * @date 创建时间： 2022/4/22 15:53
 */
@Data
public class FullyQualifiedJavaType implements Comparable<FullyQualifiedJavaType> {

    /**
     * 基础类型
     */
    private static FullyQualifiedJavaType intInstance = null;
    private static FullyQualifiedJavaType stringInstance = null;
    private static FullyQualifiedJavaType booleanPrimitiveInstance = null;
    private static FullyQualifiedJavaType objectInstance = null;
    private static FullyQualifiedJavaType dateInstance = null;
    private static FullyQualifiedJavaType criteriaInstance = null;
    private static FullyQualifiedJavaType generatedCriteriaInstance = null;


    /**
     * 基础限定名，比如 java.lang.Long
     */
    private String baseQualifiedName;
    /**
     * 是否导入进来的包，是则为true
     * 所谓的非导入进来的包指的是 java.lang 包下面的类
     */
    private Boolean explicitlyImported;
    /**
     * 包名
     * 比如 java.lang.Long ，包名为 java.lang
     */
    private String packageName;
    /**
     * 是否原始数据类型，true 则是原始数据类型
     */
    private Boolean primitive;
    /**
     * 是否数组，] 结尾的就可能是数组，
     * false 非数组, true 是数组
     */
    private Boolean isArray;
    /**
     * 是否有通配符,true 有通配符
     */
    private boolean wildcardType;
    /**
     * 有界通配符
     */
    private boolean boundedWildcard;
    /**
     * 是否扩展有界通配符
     */
    private boolean extendsBoundedWildcard;
    /**
     * java类型，比如 String, Boolean 等
     */
    private String baseShortName;

    /**
     * 泛型数据解析，如果解析的包存在泛型等会放到该list中
     */
    private List<FullyQualifiedJavaType> typeArgumentList;
    /**
     * 基础类型
     */
    private PrimitiveTypeWrapper primitiveTypeWrapper;











    /**
     * 构造方法1
     * @param fullTypeSpecification 包装器类型的完全限定名
     */
    public FullyQualifiedJavaType(String fullTypeSpecification) {
        super();
        typeArgumentList = new ArrayList<>();
        parse(fullTypeSpecification);
    }

    /**
     * 获取整型实例
     * @return
     */
    public static FullyQualifiedJavaType getIntInstance() {
        if (intInstance == null) {
            intInstance = new FullyQualifiedJavaType("int");
        }

        return intInstance;
    }

    /**
     * map对象实例
     * @return
     */
    public static FullyQualifiedJavaType getNewMapInstance() {
        return new FullyQualifiedJavaType("java.util.Map");
    }

    /**
     * list 对象实例
     * @return
     */
    public static FullyQualifiedJavaType getNewListInstance() {
        return new FullyQualifiedJavaType("java.util.List");
    }

    /**
     * hashMap 对象实例
     * @return
     */
    public static FullyQualifiedJavaType getNewHashMapInstance() {
        return new FullyQualifiedJavaType("java.util.HashMap");
    }

    /**
     * arrayList 对象实例
     * @return
     */
    public static FullyQualifiedJavaType getNewArrayListInstance() {
        return new FullyQualifiedJavaType("java.util.ArrayList");
    }

    /**
     * 迭代器 对象实例
     * @return
     */
    public static FullyQualifiedJavaType getNewIteratorInstance() {
        return new FullyQualifiedJavaType("java.util.Iterator");
    }

    /**
     * 字符串 对象实例
     * @return
     */
    public static FullyQualifiedJavaType getStringInstance() {
        if (stringInstance == null) {
            stringInstance = new FullyQualifiedJavaType("java.lang.String");
        }

        return stringInstance;
    }

    /**
     * 布尔 对象实例
     * @return
     */
    public static FullyQualifiedJavaType getBooleanPrimitiveInstance() {
        if (booleanPrimitiveInstance == null) {
            booleanPrimitiveInstance = new FullyQualifiedJavaType("boolean");
        }

        return booleanPrimitiveInstance;
    }

    /**
     * 基础对象实例
     * @return
     */
    public static FullyQualifiedJavaType getObjectInstance() {
        if (objectInstance == null) {
            objectInstance = new FullyQualifiedJavaType("java.lang.Object");
        }

        return objectInstance;
    }

    /**
     * 时间对象实例
     * @return
     */
    public static FullyQualifiedJavaType getDateInstance() {
        if (dateInstance == null) {
            dateInstance = new FullyQualifiedJavaType("java.util.Date");
        }

        return dateInstance;
    }

    /**
     * 传统sql的对象化表示Criteria
     * @return
     */
    public static FullyQualifiedJavaType getCriteriaInstance() {
        if (criteriaInstance == null) {
            criteriaInstance = new FullyQualifiedJavaType("Criteria");
        }

        return criteriaInstance;
    }

    /**
     *
     * @return
     */
    public static FullyQualifiedJavaType getGeneratedCriteriaInstance() {
        if (generatedCriteriaInstance == null) {
            generatedCriteriaInstance = new FullyQualifiedJavaType("GeneratedCriteria");
        }

        return generatedCriteriaInstance;
    }

    /**
     * 字符串是否有值
     * @param s 要验证的字符串
     * @return
     */
    public static boolean stringHasValue(String s) {
        return s != null && s.length() > 0;
    }

    /**
     * 获取包名，比如 java.lang.Long 这个，最终得到报名 java.lang
     * @param baseQualifiedName 完整名称
     * @return
     */
    private static String getPackage(String baseQualifiedName) {
        int index = baseQualifiedName.lastIndexOf('.');
        return baseQualifiedName.substring(0, index);
    }

    /**
     * 获取全限定名
     * @return
     */
    public String getFullyQualifiedName() {
        StringBuilder sb = new StringBuilder();
        // 如果通配符类型
        if (wildcardType) {
            sb.append('?');
            // 有界通配符
            if (boundedWildcard) {
                // 扩展的有界通配符
                if (extendsBoundedWildcard) {
                    sb.append(" extends ");
                } else {
                    sb.append(" super ");
                }

                sb.append(baseQualifiedName);
            }
        } else {
            sb.append(baseQualifiedName);
        }

        // 类型参数列表处理
        if (typeArgumentList.size() > 0) {
            boolean first = true;
            sb.append('<');
            for (FullyQualifiedJavaType fqjt : typeArgumentList) {
                if (first) {
                    first = false;
                } else {
                    sb.append(", ");
                }
                sb.append(fqjt.getFullyQualifiedName());

            }
            sb.append('>');
        }

        return sb.toString();
    }

    /**
     * 获取导入的列表
     * @return
     */
    public List<String> getImportList() {
        List<String> answer = new ArrayList<String>();
        if (explicitlyImported) {
            int index = baseShortName.indexOf('.');
            if (index == -1) {
                answer.add(baseQualifiedName);
            } else {
                // an inner class is specified, only import the top
                // level class
                StringBuilder sb = new StringBuilder();
                sb.append(packageName);
                sb.append('.');
                sb.append(baseShortName.substring(0, index));
                answer.add(sb.toString());
            }
        }

        for (FullyQualifiedJavaType fqjt : typeArgumentList) {
            answer.addAll(fqjt.getImportList());
        }

        return answer;
    }


    public String getShortName() {
        StringBuilder sb = new StringBuilder();
        if (wildcardType) {
            sb.append('?');
            if (boundedWildcard) {
                if (extendsBoundedWildcard) {
                    sb.append(" extends ");
                } else {
                    sb.append(" super ");
                }

                sb.append(baseShortName);
            }
        } else {
            sb.append(baseShortName);
        }

        if (typeArgumentList.size() > 0) {
            boolean first = true;
            sb.append('<');
            for (FullyQualifiedJavaType fqjt : typeArgumentList) {
                if (first) {
                    first = false;
                } else {
                    sb.append(", ");
                }
                sb.append(fqjt.getShortName());

            }
            sb.append('>');
        }

        return sb.toString();
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }

        if (!(obj instanceof FullyQualifiedJavaType)) {
            return false;
        }

        FullyQualifiedJavaType other = (FullyQualifiedJavaType) obj;

        return getFullyQualifiedName().equals(other.getFullyQualifiedName());
    }

    @Override
    public int hashCode() {
        return getFullyQualifiedName().hashCode();
    }

    @Override
    public String toString() {
        return getFullyQualifiedName();
    }

    public void addTypeArgument(FullyQualifiedJavaType type) {
        typeArgumentList.add(type);
    }

    /**
     * 解析包装器类型的完全限定名
     * @param fullTypeSpecification 包装器类型的完全限定名
     */
    private void parse(String fullTypeSpecification) {
        String spec = fullTypeSpecification.trim();

        if (spec.startsWith("?")) {
            wildcardType = true;
            spec = spec.substring(1).trim();
            if (spec.startsWith("extends ")) {
                boundedWildcard = true;
                extendsBoundedWildcard = true;
                // "extends ".length()
                spec = spec.substring(8);
            } else if (spec.startsWith("super ")) {
                boundedWildcard = true;
                extendsBoundedWildcard = false;
                // "super ".length()
                spec = spec.substring(6);
            } else {
                boundedWildcard = false;
            }
            parse(spec);
        } else {
            int index = fullTypeSpecification.indexOf('<');
            if (index == -1) {
                simpleParse(fullTypeSpecification);
            } else {
                simpleParse(fullTypeSpecification.substring(0, index));
                int endIndex = fullTypeSpecification.lastIndexOf('>');
                if (endIndex == -1) {
                    throw new RuntimeException("解析包装器类型失败(Invalid Type Specification): " + fullTypeSpecification);
                }
                genericParse(fullTypeSpecification.substring(index, endIndex + 1));
            }
            isArray = fullTypeSpecification.endsWith("]");
        }
    }

    /**
     * 简单的限定名解析
     * @param typeSpecification
     */
    private void simpleParse(String typeSpecification) {
        baseQualifiedName = typeSpecification.trim();
        if (baseQualifiedName.contains(".")) {
            packageName = getPackage(baseQualifiedName);
            baseShortName = baseQualifiedName.substring(packageName.length() + 1);
            int index = baseShortName.lastIndexOf('.');
            if (index != -1) {
                baseShortName = baseShortName.substring(index + 1);
            }

            if (MetadataConstant.Base.JAVA_LANG.equals(packageName)) {
                explicitlyImported = false;
            } else {
                explicitlyImported = true;
            }
        } else {
            baseShortName = baseQualifiedName;
            explicitlyImported = false;
            packageName = "";

            if ("byte".equals(baseQualifiedName)) {
                primitive = true;
                primitiveTypeWrapper = PrimitiveTypeWrapper.getByteInstance();
            } else if ("short".equals(baseQualifiedName)) {
                primitive = true;
                primitiveTypeWrapper = PrimitiveTypeWrapper.getShortInstance();
            } else if ("int".equals(baseQualifiedName)) {
                primitive = true;
                primitiveTypeWrapper = PrimitiveTypeWrapper.getIntegerInstance();
            } else if ("long".equals(baseQualifiedName)) {
                primitive = true;
                primitiveTypeWrapper = PrimitiveTypeWrapper.getLongInstance();
            } else if ("char".equals(baseQualifiedName)) {
                primitive = true;
                primitiveTypeWrapper = PrimitiveTypeWrapper.getCharacterInstance();
            } else if ("float".equals(baseQualifiedName)) {
                primitive = true;
                primitiveTypeWrapper = PrimitiveTypeWrapper.getFloatInstance();
            } else if ("double".equals(baseQualifiedName)) {
                primitive = true;
                primitiveTypeWrapper = PrimitiveTypeWrapper.getDoubleInstance();
            } else if ("boolean".equals(baseQualifiedName)) {
                primitive = true;
                primitiveTypeWrapper = PrimitiveTypeWrapper.getBooleanInstance();
            } else {
                primitive = false;
                primitiveTypeWrapper = null;
            }
        }
    }

    /**
     * 泛型解析
     * @param genericSpecification
     */
    private void genericParse(String genericSpecification) {
        int lastIndex = genericSpecification.lastIndexOf('>');
        if (lastIndex == -1) {
            throw new RuntimeException("无效的类型(Invalid Type Specification): " + genericSpecification);
        }
        String argumentString = genericSpecification.substring(1, lastIndex);
        // need to find "," outside of a <> bounds
        StringTokenizer st = new StringTokenizer(argumentString, ",<>", true);
        int openCount = 0;
        StringBuilder sb = new StringBuilder();
        while (st.hasMoreTokens()) {
            String token = st.nextToken();
            if ("<".equals(token)) {
                sb.append(token);
                openCount++;
            } else if (">".equals(token)) {
                sb.append(token);
                openCount--;
            } else if (",".equals(token)) {
                if (openCount == 0) {
                    typeArgumentList.add(new FullyQualifiedJavaType(sb.toString()));
                    sb.setLength(0);
                } else {
                    sb.append(token);
                }
            } else {
                sb.append(token);
            }
        }

        if (openCount != 0) {
            throw new RuntimeException("无效的类型(Invalid Type Specification): " + genericSpecification);
        }

        String finalType = sb.toString();
        if (stringHasValue(finalType)) {
            typeArgumentList.add(new FullyQualifiedJavaType(finalType));
        }
    }

    /**
     * 比较是否一样
     * @param fullyQualifiedJavaType java限定类型
     * @return
     */
    @Override
    public int compareTo(FullyQualifiedJavaType fullyQualifiedJavaType) {
        return getFullyQualifiedName().compareTo(fullyQualifiedJavaType.getFullyQualifiedName());
    }

}
